package com.event.management.backend.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.event.management.backend.domain.Event;
import com.event.management.backend.domain.Ticket;
import com.event.management.backend.dto.TicketDTO;
import com.event.management.backend.dto.TicketStatsDTO;
import com.event.management.backend.mapper.TicketMapper;
import com.event.management.backend.service.TicketService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 票种服务实现类
 */
@Service
public class TicketServiceImpl extends ServiceImpl<TicketMapper, Ticket> implements TicketService {

    @Override
    public List<TicketDTO> getTicketsByEventId(Long eventId) {
        List<Ticket> tickets = baseMapper.findByEventId(eventId);
        return tickets.stream().map(this::convertToDTO).collect(Collectors.toList());
    }

    @Override
    @Transactional
    public Long addTicket(TicketDTO ticketDTO) {
        // 检查活动是否存在
        int count = baseMapper.checkEventExists(ticketDTO.getEventId());
        if (count == 0) {
            throw new RuntimeException("关联的活动不存在");
        }
        
        // 检查操作权限
        if (!checkTicketManagePermission(ticketDTO.getEventId())) {
            throw new RuntimeException("您没有权限管理此活动的票种");
        }
        
        // 检查活动状态
        String status = baseMapper.getEventStatus(ticketDTO.getEventId());
        if (Event.EventStatus.OFFLINE.equals(status)) {
            throw new RuntimeException("活动已下线，不能添加票种");
        }
        
        // 设置初始值
        if (ticketDTO.getSoldCount() == null) {
            ticketDTO.setSoldCount(0);
        }
        if (ticketDTO.getLimitPerUser() == null) {
            ticketDTO.setLimitPerUser(1);
        }
        
        // 转换为实体并保存
        Ticket ticket = new Ticket();
        BeanUtils.copyProperties(ticketDTO, ticket);
        // 显式设置 id 为 null，确保使用数据库自增 ID
        ticket.setId(null);
        
        boolean result = save(ticket);
        if (!result) {
            throw new RuntimeException("添加票种失败");
        }
        
        return ticket.getId();
    }

    @Override
    @Transactional
    public boolean updateTicket(Long id, TicketDTO ticketDTO) {
        // 检查票种是否存在
        Ticket existingTicket = getById(id);
        if (existingTicket == null) {
            throw new RuntimeException("票种不存在");
        }
        
        // 检查操作权限
        if (!checkTicketManagePermission(existingTicket.getEventId())) {
            throw new RuntimeException("您没有权限管理此活动的票种");
        }
        
        // 检查活动状态
        String status = baseMapper.getEventStatus(existingTicket.getEventId());
        if (Event.EventStatus.OFFLINE.equals(status)) {
            throw new RuntimeException("活动已下线，不能修改票种");
        }
        
        // 不允许修改活动ID、已售数量
        ticketDTO.setEventId(existingTicket.getEventId());
        ticketDTO.setSoldCount(existingTicket.getSoldCount());
        
        // 更新实体
        Ticket ticket = new Ticket();
        BeanUtils.copyProperties(ticketDTO, ticket);
        ticket.setId(id);
        
        return updateById(ticket);
    }

    @Override
    @Transactional
    public boolean deleteTicket(Long id) {
        // 检查票种是否存在
        Ticket existingTicket = getById(id);
        if (existingTicket == null) {
            throw new RuntimeException("票种不存在");
        }
        
        // 检查操作权限
        if (!checkTicketManagePermission(existingTicket.getEventId())) {
            throw new RuntimeException("您没有权限管理此活动的票种");
        }
        
        // 检查活动状态
        String status = baseMapper.getEventStatus(existingTicket.getEventId());
        if (Event.EventStatus.OFFLINE.equals(status)) {
            throw new RuntimeException("活动已下线，不能删除票种");
        }
        
        // 如果已售票数大于0，不允许删除
        if (existingTicket.getSoldCount() != null && existingTicket.getSoldCount() > 0) {
            throw new RuntimeException("该票种已有售出记录，不能删除");
        }
        
        // 逻辑删除
        return removeById(id);
    }

    @Override
    public TicketStatsDTO getTicketStats(Long id) {
        // 查询票种信息
        Ticket ticket = getById(id);
        if (ticket == null) {
            throw new RuntimeException("票种不存在");
        }
        
        TicketStatsDTO stats = new TicketStatsDTO();
        
        // 已售数量
        Integer soldCount = ticket.getSoldCount() != null ? ticket.getSoldCount() : 0;
        stats.setSoldCount(soldCount);
        
        // 剩余数量
        Integer remainingCount = ticket.getTotalStock() - soldCount;
        stats.setRemainingCount(remainingCount);
        
        // 销售总额
        BigDecimal totalAmount = ticket.getPrice().multiply(new BigDecimal(soldCount));
        stats.setTotalAmount(totalAmount);
        
        // 销售率
        BigDecimal sellRate = BigDecimal.ZERO;
        if (ticket.getTotalStock() > 0) {
            sellRate = new BigDecimal(soldCount)
                    .divide(new BigDecimal(ticket.getTotalStock()), 4, RoundingMode.HALF_UP);
        }
        stats.setSellRate(sellRate);
        
        return stats;
    }

    @Override
    public boolean checkTicketManagePermission(Long eventId) {
        // 获取当前登录用户ID
        Long userId = StpUtil.getLoginIdAsLong();
        
        // 如果是管理员，直接返回true
        if (StpUtil.hasRole("admin")) {
            return true;
        }
        
        // 检查是否是活动创建者
        int count = baseMapper.checkIsEventCreator(eventId, userId);
        return count > 0;
    }

    @Override
    public TicketDTO getTicketById(Long id) {
        Ticket ticket = getById(id);
        if (ticket == null) {
            return null;
        }
        
        return convertToDTO(ticket);
    }
    
    /**
     * 将实体转换为DTO
     * @param ticket 票种实体
     * @return 票种DTO
     */
    private TicketDTO convertToDTO(Ticket ticket) {
        TicketDTO dto = new TicketDTO();
        BeanUtils.copyProperties(ticket, dto);
        return dto;
    }
} 